#include <fermat/common/shared_library.h>
#include <fermat/common/scoped_lock.h>
#include <dlfcn.h>
#include <assert.h>

namespace fermat {

Mutex SharedLibrary::_mutex;

SharedLibrary::SharedLibrary()
{
	_handle = 0;
}


SharedLibrary::SharedLibrary(const std::string& path)
{
	_handle = 0;
	loadImpl(path, 0);
}


SharedLibrary::SharedLibrary(const std::string& path, int flags)
{

	_handle = 0;
	loadImpl(path, flags);
}


SharedLibrary::~SharedLibrary()
{
}


void SharedLibrary::load(const std::string& path)
{
	loadImpl(path, 0);	
}


void SharedLibrary::load(const std::string& path, int flags)
{
	loadImpl(path, flags);
}


void SharedLibrary::unload()
{
	ScopedMutex lock(&_mutex);
	if (_handle) {
		dlclose(_handle);
		_handle = 0;
	}
}


bool SharedLibrary::isLoaded() const
{
	return _handle != 0; 
}


bool SharedLibrary::hasSymbol(const std::string& name)
{
	return getSymbol(name) != 0;
}


void* SharedLibrary::getSymbol(const std::string& name)
{
	ScopedMutex lock(&_mutex);
	void* result = 0;
	if (_handle) {
		result = dlsym(_handle, name.c_str());
	}
	return result;
}


const std::string& SharedLibrary::getPath() const
{
	return _path;
}


std::string SharedLibrary::prefix()
{
	return "lib";
}


std::string SharedLibrary::suffix()
{
	return ".so";
}

std::string SharedLibrary::getOSName(const std::string& name) 
{
	return prefix() + name + suffix();
}
bool SharedLibrary::loadImpl(const std::string &path, int flags)
{
	
	ScopedMutex lock(&_mutex);
	if (_handle) {
		return false;
	}
	int realFlags = RTLD_LAZY;
	if (flags & SHLIB_LOCAL) {
		realFlags |= RTLD_LOCAL;
	} else {
		realFlags |= RTLD_GLOBAL;
	}

	_handle = dlopen(path.c_str(), realFlags);
	if (!_handle) {
		_errmsg = dlerror();
		return false;	
	}
	_path = path;
	_errmsg.clear();
	 return true;
}

} 